package org.NooLab.tikaserver.tcp.agents;

import java.util.Observable;
import java.util.Observer;

 
import org.NooLab.tikaserver.TikaServerFactory;
import org.NooLab.tikaserver.intf.TikaSrvCmdPkgIntf;
import org.NooLab.tikaserver.intf.TikaSrvDataTransferPkgIntf;
import org.NooLab.tikaserver.tcp.agents.TcpPrimaryClient.MessageReceiver;
import org.NooLab.tikaserver.tcp.agents.data.Data;
import org.NooLab.tikaserver.tcp.agents.data.DataIntf;
import org.NooLab.tikaserver.tcp.box.TcpBox;
import org.NooLab.tikaserver.tcp.box.infra.DataReceiverIntf;
import org.NooLab.tikaserver.tcp.box.infra.DataSenderIntf;
import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.objects.StringedObjects;




public class TikaServerAgent implements Observer{
 
	int senderPort ; 
	int listeningPort ;
	
	TikaServerFactory tsFactory;
	
	TcpBox tcpBox;
	MessageReceiver msgReceiver;

	DataReceiverIntf receiverDevice;
	DataSenderIntf senderDevice;
	
	StringedObjects sob = new StringedObjects();
	PrintLog out = new PrintLog(2,true);
	private TikaServerAgent serverAgent;
	
	// ========================================================================
	public TikaServerAgent( TikaServerFactory factory, int senderPort, int listeningPort ){
		
		this.senderPort = senderPort;
		this.listeningPort = listeningPort ;
	
		tcpBox = new TcpBox();
		msgReceiver = new MessageReceiver();

		tsFactory = factory ;
		
		serverAgent = this ;
	}
	// ========================================================================
	
	public void close(){
		
		receiverDevice.deleteObservers();
		receiverDevice.closePort() ;
		
		if (senderDevice!=null){
			senderDevice.release();
		}
		tcpBox.deleteObservers() ;
	}
	
	public void start( ) {
		
		senderDevice = tcpBox.createSender(senderPort, listeningPort, "") ;
		receiverDevice = tcpBox.createReceiver(listeningPort, senderPort, msgReceiver, "") ;
	}
	

	@Override
	public void update(Observable arg0, Object dataobj) {
		 
		TikaSrvDataTransferPkgIntf data = (TikaSrvDataTransferPkgIntf)dataobj;
		senderDevice.send( sob.encode(data), data.getGuid() );
	}


	class MessageReceiver implements Observer{

		@Override
		public void update(Observable srv, Object dataObj) {
			
			int confcode;
			String filename, suid;
			String[] dataPkg;
			
			Object obj;
			TikaSrvDataTransferPkgIntf data = null; 
			//TikaSrvDataTransferPkgIntf dataTransferPkg;
			// TikaSrvCmdPkgIntf command;
			TextProducer txtProduce = null;
			
			               // out.print(2, "S: "+srv.toString().replace("org.NooLab.", "")) ;
				
			// the outer data package is internal to the tcp transfer infrastructure
			dataPkg = (String[])dataObj ;
			
			// ...it contains a GUID at [0] ...
			suid = dataPkg[0] ;
			 
			obj = sob.decode( dataPkg[1] );
			
			if (obj instanceof TikaSrvCmdPkgIntf){
				
				performCommand((TikaSrvCmdPkgIntf)obj,suid);
				return;
			}
			/*
			 *  ... and a very simple generic container at [1]... which we must further decode...
			 *  the data is specific for TikaServer, 
			 *  it is an object that contains control params and data 
			 */
			if (obj instanceof TikaSrvDataTransferPkgIntf){
				data = (TikaSrvDataTransferPkgIntf)obj;
			}
			
			if (data == null){
				// returning an error message via tcp
				confcode = TikaSrvDataTransferPkgIntf._TRANSFER_CONFIRMATION_GENERALFAIL  ;
			}
			
			if (data != null){
				
								// out.print(2, "S: " + v);
				int datatype = data.getTypeOfData();
				
				if (datatype == TikaSrvDataTransferPkgIntf._TRANSFER_DATA_TYPE_LOCALFILE){
					filename = data.getFilename();
					// this filename MUST be local!!! remote docs must be imported to a 
					// local context before
					
					if (DFutils.fileExists(filename)){
						
											out.print(4, "recognized correct filename...");
						// here creating a process that later will send the data object filled with its text
						txtProduce = new TextProducer( tsFactory, serverAgent, data );
						
						// it will return immediately, results are then to be found in the update() method

						confcode = TikaSrvDataTransferPkgIntf._TRANSFER_CONFIRMATION_SOURCEOK  ;
					}else{
						confcode = TikaSrvDataTransferPkgIntf._TRANSFER_CONFIRMATION_SOURCEFAIL ; 
					}
					data.setConfirmationCode(confcode);
				} // _TRANSFER_DATA_TYPE_LOCALFILE ?
				
				data.setGuid( suid ) ; 
				/*
				 * effectively, this links the domains cross-wise!
				 * when creating the package client-side, this guid is not known, hence it is not part
				 * of the data package.
				 * the client, however, puts it into a delivery queue, and against this queue the status
				 * will be checked
				 *  
				 */
				                        
				
				if (data.getBinData()!=null){
					data.setBinData(null);
				}
			} 
			 
											out.print(4, "TikaServer, returning confirmation code...");
			senderDevice.send( sob.encode(data),dataPkg[0]);
			
			if (txtProduce!=null){
				txtProduce.close();
				out.delay(5);
				txtProduce = null;
			}
		}

		private void performCommand(TikaSrvCmdPkgIntf cmdObj, String suid) {
			 
			if (cmdObj.getStop()>=1){
				
				out.printErr(1, "TikaServer received a request for exit, stopping now...");
				senderDevice.release() ;
				receiverDevice.closePort() ;
				out.delay(500);
				System.exit(2);
			}
			if (cmdObj.getRestart()>=1){
				
				return;
			}
			if (cmdObj.getPing()>=1){
				senderDevice.send( sob.encode(cmdObj),suid);
			}
		}
		
	}


	public boolean receiverIsNull() {
		 
		return (receiverDevice==null);
	}
}